#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2020/4/23 0023 1:04
# @Author  : liangshuo
# @File    : views.py
# @Software : PyCharm
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
# mixins视图中的6大工具类
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework.mixins import DestroyModelMixin  # 禁止使用(真正从数据库删除了数据），要重写
# generic的工具视图
from rest_framework.generics import ListCreateAPIView, UpdateAPIView
# viewset视图集
from rest_framework.viewsets import GenericViewSet

from .models import Book
from .serializers import BookModelSerializer
from utils.response import APIResponse


# APIView
# 1）as_view干了什么事情
# 2）dispatch干了什么事
# 3）APIView上面的全局配置
class BookAPIView(APIView):
    def get(self, request, *args, **kwargs):
        book_queryset = Book.objects.filter(is_deleted=False).all()
        book_serializer = BookModelSerializer(book_queryset, many=True)
        book_data = book_serializer.data

        return APIResponse(results=book_data)


# GenericAPIView是继承APIView的，使用完全兼容APIView
# 重点：GenericAPIView在APIView基础上完成了哪些事情
# 三个方法
# 1) get_queryset()：从类属性queryset中获得model的queryset数据
# 2) get_object()：从类属性中queryset中获得model的queryset数据，再通过有名分组pk确定唯一操作对象
# 3) get_serializer()：从类属性serializer_class中获得Serializer的序列化类
# 两个属性
#     queryset = None  # get_queryset()会使用
#     serializer_class = None  # get_serializer() 使用
class BookGenericAPIView(GenericAPIView):
    queryset = Book.objects.filter(is_deleted=False)  # 默认.all()
    serializer_class = BookModelSerializer
    # 自定义主键的，有名分组名
    lookup_field = 'pk'  # 服务于get_object()

    # 可配置为id,同时还有修改url中的pk

    # 001-群取
    def get1(self, request, *args, **kwargs):
        book_queryset = self.get_queryset()
        book_serializer = self.get_serializer(book_queryset, many=True)
        book_data = book_serializer.data
        return APIResponse(results=book_data)

    # 002-单取
    def get2(self, request, *args, **kwargs):
        book_queryset = self.get_object()
        book_serializer = self.get_serializer(book_queryset, many=False)
        book_data = book_serializer.data
        return APIResponse(results=book_data)

    # 003-群取，单取, 统一接口
    def get22(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            return self.retrieve(self, request, *args, **kwargs)
        else:
            return self.list(self, request, *args, **kwargs)

    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)
        data = serializer.data
        return APIResponse(results=data)

    def retrieve(self, request, *args, **kwargs):
        queryset = self.get_object()
        serializer = self.get_serializer(queryset, many=False)
        data = serializer.data
        return APIResponse(results=data)


# mixins视图工具类
# 1）mixins视图有5个工具类文件，一共提供了5个工具类，6个工具方法：群查，单查，单增，单-整体改，单-局部改，单删（禁止用）
# 2）继承工具类，可以简化请求函数 实现体，但是必须继承GenericAPIView，需要GenericAPIView类提供的几个类属性和方法(见上方的GenericAPIView）
# 3）工具类的工具方法返回值都是Response类型对象，如果要格式化数据格式再返回给前台，可以通过response.data拿到工具方法返回的数据
class BookMixinsGenericAPIView(ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericAPIView):
    queryset = Book.objects.filter(is_deleted=False)  # 默认.all()
    serializer_class = BookModelSerializer

    # 群查
    def get1(self, request, *args, **kwargs):
        # mixnis提供的list方法的响应对象是Response，如何将该对象格式化为APIResponse（自己的response）？
        response = self.list(request, *args, **kwargs)
        print(response.data)  # response的数据都存放在response.data中
        return APIResponse(results=response.data)

    # 单查，群查
    def get(self, request, *args, **kwargs):
        if 'pk' in kwargs:
            response = self.retrieve(request, *args, **kwargs)
        else:
            response = self.list(request, *args, **kwargs)
        return APIResponse(results=response.data)

    def post(self, request, *args, **kwargs):
        # return self.create(self, request, *args, **kwargs)  # 把self传给request了
        response = self.create(request, *args, **kwargs)
        return APIResponse(results=response.data)

    def put(self, request, *args, **kwargs):
        response = self.update(request, *args, **kwargs)  # 单个，整体修改
        return APIResponse(results=response.data)

    def patch(self, request, *args, **kwargs):
        response = self.partial_update(request, *args, **kwargs)  # 单个，局部修改
        return APIResponse(results=response.data)

    # delete方法需要重写
    def delete(self, request, *args, **kwargs):
        pass


# generic的工具视图
# 1) 工具视图都是GenericAPIView的子类，且不同的子类继承不同的mixins工具类,重写了请求方法
# ListCreateAPIView  群查-单增 ， UpdateAPIView  单更新
# 2）工具视图的功能如果直接可以满足需求，只需要继承工具视图，提供queryset和serializer_class即可
class BookListCreateUpdateAPIView(ListCreateAPIView, UpdateAPIView):
    queryset = Book.objects.filter(is_deleted=False)  # 默认.all()
    serializer_class = BookModelSerializer


# viewset视图集
# 1) 视图集都是优先继承ViewSetMixin类，再继承一个视图类（GenericAPIView或APIView）
# 2) ViewSetMixin提供了重写as_view()方法，继承视图集的视图类，配置路由时调用as_view()必须传入   请求---函数名  映射关系字典
# eg：     re_path(r'^v5book/$', BookGenericViewSet.as_view({'get': 'my_get_list'})),
# 表示 get方法会交给my_get_list视图函数处理
from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet


class BookGenericViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet):
    queryset = Book.objects.filter(is_deleted=False)  # 默认.all()
    serializer_class = BookModelSerializer

    # 群查
    def my_get_list1(self, request, *args, **kwargs):
        return APIResponse(data_status=0, data_msg='my get list ok')

    # 单查
    def my_get_obj2(self, request, *args, **kwargs):
        return APIResponse(data_status=0, data_msg='my get obj ok')

    # 群查vs单查
    # 不加任何逻辑的单查群查共存
    # 解耦，10个函数对应不同10个不同method方法
    def my_get_list(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def my_get_obj(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)


# 类似于：C/S  B/S
# APIView 和 GenericAPIVIew 作为两大继承视图的区别
# 1） GenericViewSet和ViewSet都继承了ViewSetMixins，as_view都可以配置 请求--函数 映射
# 2） GenericViewSet 继承的是GenericAPIVIew视图类， 用来完成标准的model类操作接口
# 3） ViewSet继承的是APIView视图类， 用来完成 不需要model类参与，或是非标准的model类操作接口
#           post 请求在标准的model类操作下是新增接口，登录的post不满足
#           post 请求验证码的接口，不需要model类的参与
# 案例：登录的post请求，并不是完整数据的新增，只是用post提交数据，得到的结果也不是登录的用户信息，而是登录的认证而已


# ModelViewSet
# 拥有六大接口：单查、群查、单增、单删、单整体改、单局部改
# 注：一般都会重写 destroy方法
from rest_framework.viewsets import ModelViewSet


class BookModelViewSet(ModelViewSet):
    queryset = Book.objects.filter(is_deleted=False)  # 默认.all()
    serializer_class = BookModelSerializer

    # 删除不是数据库的物理删除，而是该记录中的删除字段，逻辑删除
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()  # type model.Book
        # if not instance:
        #     return APIResponse(data_status=1, results='删除失败')  # 实际操作，在此之前就做了判断

        instance.is_deleted = True
        instance.save()
        return APIResponse(data_status=0, results='删除成功')
